//****************************************************
// Porman Project 
// Filename: CRSDef.h
// Date: 2010/12/13
// Author: KengYu Lin
// Modify:
//****************************************************
#ifndef _CRSDEF_H
#define _CRSDEF_H

#ifdef WIN32
    #include <windows.h>
    #ifdef PRS_EXPORT
        #define PRS_API __declspec(dllexport)
    #else
        #define PRS_API __declspec(dllimport)
    #endif
#else
    #define PRS_API
#endif
#include <map>
#include <assert.h>

#define SAFEDELETE(x) delete x; x = NULL
#define SAFEDELETE_ARRAY(x) delete[]x; x = NULL
#define MUTEXLOCK() CRenderMutexObject( CRenderSystem::getSingleton().getMutexRef() )

namespace Porman
{

namespace GL
{
class CDeviceDesc;
}//End namespace GL

namespace RS
{

typedef GL::CDeviceDesc CRenderSystemDesc;

//-------------------------------------
// common class:
//-------------------------------------
class IRenderMutex
{
public:
    IRenderMutex( void ) {}
    virtual void lock( void ) const = 0;
    virtual void unlock( void ) const = 0;

protected:
    IRenderMutex( const IRenderMutex& l );
    IRenderMutex& operator=( const IRenderMutex& l );
};

class CDefaultRenderMutex : public IRenderMutex
{
#ifdef WIN32
public:
    PRS_API CDefaultRenderMutex( void ) 
    {
        m_cs = new CRITICAL_SECTION; 
        if( m_cs ) 
            InitializeCriticalSection( m_cs ); 
    }

    PRS_API virtual ~CDefaultRenderMutex( void ) 
    {
        if( m_cs )
        {
            DeleteCriticalSection( m_cs );
            delete m_cs;
        }
    }

    PRS_API virtual void lock( void ) const
    {
        if( m_cs )
           EnterCriticalSection( m_cs );
    }
    
    PRS_API virtual void unlock( void ) const
    {
        if( m_cs )
            LeaveCriticalSection( m_cs );
    }

protected:
    CRITICAL_SECTION* m_cs;
#else // Other platform implementation:
public:
    PRS_API CDefaultRenderMutex( void ) {}
    PRS_API virtual ~CDefaultRenderMutex( void ) {}
    PRS_API virtual void lock( void ) const {}
    PRS_API virtual void unlock( void ) const {}

protected:
    void* m_cs;
#endif
};

class CRenderMutexObject
{
public:
    PRS_API CRenderMutexObject( const IRenderMutex* pMutex )
    {
        m_pMutex = pMutex;
        m_pMutex->lock();
    }

    PRS_API ~CRenderMutexObject( void )
    {
        m_pMutex->unlock();
    }

protected:
    const IRenderMutex* m_pMutex;
};

//-------------------------------------
// template class:
//-------------------------------------
template<typename T> class CSingletonT
{
public:
    CSingletonT( void )
    {
        assert( !ms_Singleton );
	    ms_Singleton = static_cast< T* >( this );
    }

    ~CSingletonT( void )
    {  
        assert( ms_Singleton );  
        ms_Singleton = 0;  
    }

    static T& getSingleton( void )
	{	
        assert( ms_Singleton );  
        return ( *ms_Singleton ); 
    }

    static T* getSingletonPtr( void )
	{
        assert( ms_Singleton );  
        return ms_Singleton; 
    }

private:
	CSingletonT(const CSingletonT<T> &);
	CSingletonT& operator=(const CSingletonT<T> &);

protected:
    static T* ms_Singleton;
};

template<typename T> T* CSingletonT<T>::ms_Singleton = NULL;

template<typename T> class CDataHandlerT
{
public:
    CDataHandlerT( void )
    {
        m_pCurData = &m_DataA;
        m_pRenderData = &m_DataB;
    }

    T& getData( void ) { return (*m_pCurData); }
    T* getDataRef( void ) { return m_pCurData; }
    T& getRenderData( void ) { return (*m_pRenderData); }
    T* getRenderDataRef( void ) { return m_pRenderData; }

    void swap( void )
    {
        if( m_pCurData == &m_DataA )
        {
            m_pCurData = &m_DataB;
            m_pRenderData = &m_DataA;
        }
        else
        {
            m_pCurData = &m_DataA;
            m_pRenderData = &m_DataB;
        }
    }

protected:
    T m_DataA, m_DataB;
    T* m_pCurData;
    T* m_pRenderData;
};

}//End namespace RS

}//End namespace Porman

#endif